/*
REWRITTEN FROM SCRATCH BY PUSSYWIZARD, IT OWNS NOW!
*/

#include "ScriptPCH.h"
#include "halls_of_reflection.h"
#include "Transport.h"
#include "MapManager.h"

class UtherBatteredHiltEvent : public BasicEvent
{
    public:
        UtherBatteredHiltEvent(Creature& owner, uint8 eventId) : _owner(owner), _eventId(eventId) { }

        bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/)
        {
            switch (_eventId)
			{
				case 1:
					_owner.UpdatePosition(5300.53f, 1987.80f, 707.70f, 3.89f, true);
					_owner.StopMovingOnCurrentPos();
					_owner.GetMotionMaster()->Clear();
					_owner.SetVisible(true);
					_owner.NearTeleportTo(5300.53f, 1987.80f, 707.70f, 3.89f);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, 2), _owner.m_Events.CalculateTime(1000));
					break;
				case 2:
					_owner.AI()->Talk(SAY_BATTERED_HILT_HALT);
					break;
				case 3:
					_owner.CastSpell((Unit*)NULL, 69966, true);
					_owner.AI()->Talk(SAY_BATTERED_HILT_REALIZE);
					if (InstanceScript* instance = _owner.GetInstanceScript())
						instance->SetData(DATA_BATTERED_HILT, 4);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, 4), _owner.m_Events.CalculateTime(3500));
					break;
				case 4:
					_owner.SetWalk(false);
					_owner.GetMotionMaster()->MovePoint(0, 5337.53f, 1981.21f, 709.32f);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, 5), _owner.m_Events.CalculateTime(6000));
					break;
				case 5:
					_owner.SetFacingTo(2.82f);
					_owner.SetStandState(UNIT_STAND_STATE_KNEEL);
					break;
				case 6:
					if (InstanceScript* instance = _owner.GetInstanceScript())
						instance->SetData(DATA_BATTERED_HILT, 6);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, 7), _owner.m_Events.CalculateTime(2000));
					break;
				case 7:
					if (InstanceScript* instance = _owner.GetInstanceScript())
						instance->SetData(DATA_BATTERED_HILT, 7);
					_owner.AI()->Talk(SAY_BATTERED_HILT_PREPARE);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, 8), _owner.m_Events.CalculateTime(4000));
					break;
				case 8:
					_owner.SetReactState(REACT_AGGRESSIVE);
					_owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
					if (InstanceScript* instance = _owner.GetInstanceScript())
						instance->SetData(DATA_BATTERED_HILT, 8);
					break;
				case 9:
					_owner.AI()->Talk(SAY_BATTERED_HILT_OUTRO1);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, _eventId+1), _owner.m_Events.CalculateTime(11000));
					break;
				case 10:
					_owner.AI()->Talk(SAY_BATTERED_HILT_OUTRO2);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, _eventId+1), _owner.m_Events.CalculateTime(7500));
					break;
				case 11:
					_owner.AI()->Talk(SAY_BATTERED_HILT_OUTRO3);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, _eventId+1), _owner.m_Events.CalculateTime(8000));
					break;
				case 12:
					_owner.AI()->Talk(SAY_BATTERED_HILT_OUTRO4);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, _eventId+1), _owner.m_Events.CalculateTime(5000));
					break;
				case 13:
					_owner.CastSpell((Unit*)NULL, 73036, true);
					_owner.m_Events.AddEvent(new UtherBatteredHiltEvent(_owner, _eventId+1), _owner.m_Events.CalculateTime(3000));
					break;
				case 14:
					{
						Position homePos = _owner.GetHomePosition();
						_owner.SetReactState(REACT_PASSIVE);
						_owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
						_owner.SetVisible(false);
						_owner.UpdatePosition(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), homePos.GetOrientation(), true);
						_owner.StopMovingOnCurrentPos();
						_owner.GetMotionMaster()->Clear();
						if (InstanceScript* instance = _owner.GetInstanceScript())
							instance->SetData(DATA_BATTERED_HILT, 9);
					}
					break;
			}
            return true;
        }

    private:
        Creature& _owner;
		uint8 _eventId;
};

class instance_halls_of_reflection : public InstanceMapScript
{
public:
	instance_halls_of_reflection() : InstanceMapScript("instance_halls_of_reflection", 668) { }

	InstanceScript* GetInstanceScript(InstanceMap* pMap) const
	{
		return new instance_halls_of_reflection_InstanceMapScript(pMap);
	}

	struct instance_halls_of_reflection_InstanceMapScript : public InstanceScript
	{
		instance_halls_of_reflection_InstanceMapScript(Map* pMap) : InstanceScript(pMap) {};

		uint32 EncounterMask;
		TeamId TeamIdInInstance;
		uint64 NPC_FalricGUID;
		uint64 NPC_MarwynGUID;
		uint64 NPC_LichKingIntroGUID;
		uint64 NPC_LeaderIntroGUID;
		uint64 NPC_GuardGUID;
		uint64 NPC_UtherGUID;
		uint64 NPC_LichKingGUID;
		uint64 NPC_LeaderGUID;
		uint64 NPC_IceWallTargetGUID[4];
		uint64 NPC_AltarBunnyGUID;
		uint64 NPC_QuelDelarGUID;
		uint64 NPC_ShipCaptainGUID;
		uint64 GO_FrostmourneGUID;
		uint64 GO_FrostmourneAltarGUID;
		uint64 GO_FrontDoorGUID;
		uint64 GO_ArthasDoorGUID;
		uint64 GO_CaveInGUID;
		uint64 GO_DoorBeforeThroneGUID;
		uint64 GO_DoorAfterThroneGUID;
		uint64 GO_IceWallGUID;

		uint64 NPC_TrashGUID[NUM_OF_TRASH];
		bool TrashActive[NUM_OF_TRASH];
		uint8 TrashCounter;
		uint32 chosenComposition[8][5];
		uint8 WaveNumber;
		uint32 NextWaveTimer;
		uint16 CheckPlayersTimer;
		uint16 ResumeFirstEventTimer;
		uint8 ResumeFirstEventStep;
		bool bFinished5Waves;
		uint8 reqKillCount;
		bool IsDuringLKFight;
		uint32 BatteredHiltStatus;

		uint64 NPC_FrostswornGeneralGUID;
		uint64 NPC_SpiritualReflectionGUID[5];

		uint32 outroTimer;
		uint8 outroStep;
		MotionTransport* T1;

		void Initialize()
		{
			EncounterMask = 0;
			TeamIdInInstance = TEAM_NEUTRAL;
			NPC_FalricGUID = 0;
			NPC_MarwynGUID = 0;
			NPC_LichKingIntroGUID = 0;
			NPC_LeaderIntroGUID = 0;
			NPC_GuardGUID = 0;
			NPC_UtherGUID = 0;
			NPC_LichKingGUID = 0;
			NPC_LeaderGUID = 0;
			memset(&NPC_IceWallTargetGUID, 0, sizeof(NPC_IceWallTargetGUID));
			NPC_AltarBunnyGUID = 0;
			NPC_QuelDelarGUID = 0;
			NPC_ShipCaptainGUID = 0;
			GO_FrostmourneGUID = 0;
			GO_FrostmourneAltarGUID = 0;
			GO_FrontDoorGUID = 0;
			GO_ArthasDoorGUID = 0;
			GO_CaveInGUID = 0;
			GO_DoorBeforeThroneGUID = 0;
			GO_DoorAfterThroneGUID = 0;
			GO_IceWallGUID = 0;

			memset(&NPC_TrashGUID, 0, sizeof(NPC_TrashGUID));
			memset(&TrashActive, 0, sizeof(TrashActive));
			TrashCounter = 0;
			memset(&chosenComposition, 0, sizeof(chosenComposition));
			WaveNumber = 0;
			NextWaveTimer = 0;
			CheckPlayersTimer = 5000;
			ResumeFirstEventTimer = 0;
			ResumeFirstEventStep = 0;
			bFinished5Waves = false;
			reqKillCount = 0;
			IsDuringLKFight = false;
			BatteredHiltStatus = 0;

			NPC_FrostswornGeneralGUID = 0;
			memset(&NPC_SpiritualReflectionGUID, 0, sizeof(NPC_SpiritualReflectionGUID));

			outroTimer = 0;
			outroStep = 0;
			T1 = NULL;
		}

		bool IsEncounterInProgress() const
		{
			return (instance->HavePlayers() && WaveNumber)  || IsDuringLKFight; // during LK fight npcs are active and will unset this variable
		}

		void OnCreatureCreate(Creature* creature)
		{
			if (TeamIdInInstance == TEAM_NEUTRAL)
			{
				Map::PlayerList const &players = instance->GetPlayers();
				if (!players.isEmpty())
					for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
						if (Player* p = itr->GetSource())
							if (!p->IsGameMaster())
							{
								TeamIdInInstance = p->GetTeamId();
								break;
							}
			}

			switch(creature->GetEntry())
			{
				case NPC_SYLVANAS_PART1:
					creature->SetVisible(false);
					NPC_LeaderIntroGUID = creature->GetGUID();
					if (TeamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_JAINA_PART1);
					creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
					creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
					break;
				case NPC_DARK_RANGER_LORALEN:
					creature->SetVisible(false);
					NPC_GuardGUID = creature->GetGUID();
					if (TeamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_ARCHMAGE_ELANDRA);
					break;
				case NPC_UTHER:
					creature->SetVisible(false);
					NPC_UtherGUID = creature->GetGUID();
					creature->SetReactState(REACT_PASSIVE);
					break;
				case NPC_LICH_KING_EVENT:
					creature->SetVisible(false);
					NPC_LichKingIntroGUID = creature->GetGUID();
					creature->SetReactState(REACT_PASSIVE);
					creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
					break;
				case NPC_FALRIC:
					creature->SetVisible(false);
					NPC_FalricGUID = creature->GetGUID();
					creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
					break;
				case NPC_MARWYN:
					creature->SetVisible(false);
					NPC_MarwynGUID = creature->GetGUID();
					creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
					break;
				case NPC_WAVE_MERCENARY:
				case NPC_WAVE_FOOTMAN:
				case NPC_WAVE_RIFLEMAN:
				case NPC_WAVE_PRIEST:
				case NPC_WAVE_MAGE:
					if (TrashCounter < NUM_OF_TRASH)
						NPC_TrashGUID[TrashCounter++] = creature->GetGUID();
					if (!(EncounterMask & (1 << DATA_MARWYN)) && !creature->IsAlive())
						creature->Respawn();
					creature->SetVisible(false);
					break;
				case NPC_FROSTSWORN_GENERAL:
					if (!(EncounterMask & (1 << DATA_MARWYN)))
					{
						creature->SetVisible(false);
						creature->SetReactState(REACT_PASSIVE);
					}
					NPC_FrostswornGeneralGUID = creature->GetGUID();
					break;
				case NPC_SPIRITUAL_REFLECTION:
					for (uint8 i=0; i<5; ++i)
						if (!NPC_SpiritualReflectionGUID[i])
						{
							NPC_SpiritualReflectionGUID[i] = creature->GetGUID();
							break;
						}
					creature->SetVisible(false);
					break;
				case NPC_LICH_KING_BOSS:
					if (!(EncounterMask & (1 << DATA_FROSTSWORN_GENERAL)))
						creature->SetVisible(false);
					if (!(EncounterMask & (1 << DATA_LK_INTRO)))
					{
						creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT);
						if (TeamIdInInstance != TEAM_ALLIANCE)
						{
							creature->StopMoving();
							creature->SetFacingTo(creature->GetAngle(&SylvanasFightPos));
						}
					}
					else if (!(EncounterMask & (1 << DATA_LICH_KING)))
						creature->AddAura(TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature);
					else
						creature->SetVisible(false);

					NPC_LichKingGUID = creature->GetGUID();
					creature->SetHealth((creature->GetMaxHealth()*3)/4);
					creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
					break;
				case NPC_SYLVANAS_PART2:
					if (!creature->IsAlive())
						creature->Respawn();
					NPC_LeaderGUID = creature->GetGUID();
					if (TeamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_JAINA_PART2);
					creature->SetHealth(creature->GetMaxHealth()/20);

					if (!(EncounterMask & (1 << DATA_FROSTSWORN_GENERAL)))
						creature->SetVisible(false);
					if (!(EncounterMask & (1 << DATA_LK_INTRO)))
					{
						creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, TeamIdInInstance == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H);
						creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
						creature->CastSpell(creature, TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true);
						if (TeamIdInInstance != TEAM_ALLIANCE)
						{
							creature->UpdatePosition(SylvanasFightPos, true);
							creature->StopMovingOnCurrentPos();
						}
					}
					else if (!(EncounterMask & (1 << DATA_LICH_KING)))
					{
						creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
						creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
						creature->UpdatePosition(LeaderEscapePos, true);
						creature->StopMovingOnCurrentPos();
					}
					else
					{
						instance->LoadGrid(PathWaypoints[PATH_WP_COUNT-1].GetPositionX(), PathWaypoints[PATH_WP_COUNT-1].GetPositionY());
						creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT-1], true);
						creature->StopMovingOnCurrentPos();
					}
					creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
					break;
				case NPC_ICE_WALL_TARGET:
					if (creature->GetPositionX() > 5525.0f)
						NPC_IceWallTargetGUID[0] = creature->GetGUID();
					else if (creature->GetPositionX() > 5475.0f)
						NPC_IceWallTargetGUID[1] = creature->GetGUID();
					else if (creature->GetPositionX() > 5400.0f)
						NPC_IceWallTargetGUID[2] = creature->GetGUID();
					else
						NPC_IceWallTargetGUID[3] = creature->GetGUID();
					break;
				case NPC_ALTAR_BUNNY:
					NPC_AltarBunnyGUID = creature->GetGUID();
					break;
				case NPC_QUEL_DELAR:
					NPC_QuelDelarGUID = creature->GetGUID();
					creature->SetReactState(REACT_PASSIVE);
					break;
				case NPC_HIGH_CAPTAIN_JUSTIN_BARLETT:
				case NPC_SKY_REAVER_KORM_BLACKSKAR:
					NPC_ShipCaptainGUID = creature->GetGUID();
					break;
			}
		}

		void OnGameObjectCreate(GameObject* go)
		{
			switch(go->GetEntry())
			{
				case GO_FROSTMOURNE:
					GO_FrostmourneGUID = go->GetGUID();
					HandleGameObject(0, false, go);
					if (EncounterMask & (1 << DATA_INTRO))
						go->SetPhaseMask(2, true);
					break;
				case GO_FROSTMOURNE_ALTAR:
					GO_FrostmourneAltarGUID = go->GetGUID();
					break;
				case GO_FRONT_DOOR:
					GO_FrontDoorGUID = go->GetGUID();
					HandleGameObject(0, true, go);
					break;
				case GO_ARTHAS_DOOR:
					GO_ArthasDoorGUID = go->GetGUID();
					HandleGameObject(0, (EncounterMask & (1 << DATA_MARWYN)), go);
					break;
				case GO_CAVE_IN:
					GO_CaveInGUID = go->GetGUID();
					break;
				case GO_DOOR_BEFORE_THRONE:
					GO_DoorBeforeThroneGUID = go->GetGUID();
					break;
				case GO_DOOR_AFTER_THRONE:
					GO_DoorAfterThroneGUID = go->GetGUID();
					break;
				case GO_ICE_WALL:
					GO_IceWallGUID = go->GetGUID();
					break;
			}
		}

		void SetData(uint32 type, uint32 data)
		{
			switch(type)
			{
				case DATA_INTRO:
					EncounterMask |= (1 << DATA_INTRO);
					AddWave1();
					break;
				case ACTION_SHOW_TRASH:
					RandomizeCompositionsAndShow();
					break;
				case DATA_FALRIC:
					if (WaveNumber)
					{
						if (data == NOT_STARTED)
							DoWipe1();
						else if (data == DONE)
						{
							NextWaveTimer = 60000;
							EncounterMask |= (1 << DATA_FALRIC);
						}
					}
					break;
				case DATA_MARWYN:
					if (WaveNumber)
					{
						if (data == NOT_STARTED)
							DoWipe1();
						else if (data == DONE)
						{
							EncounterMask |= (1 << DATA_MARWYN);
							HandleGameObject(GO_FrontDoorGUID, true);
							HandleGameObject(GO_ArthasDoorGUID, true);
							if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID))
							{
								c->SetVisible(true);
								c->SetReactState(REACT_AGGRESSIVE);
							}
							WaveNumber = 0;
							DoUpdateWorldState(WORLD_STATE_HOR_COUNTER, 0);

							// give quest
							Map::PlayerList const& pl = instance->GetPlayers();
							for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
								if (Player* p = itr->GetSource())
									p->CastSpell(p, p->GetTeamId() == TEAM_ALLIANCE ? SPELL_HOR_START_QUEST_ALLY : SPELL_HOR_START_QUEST_HORDE, true);
						}
					}
					break;
				case DATA_FROSTSWORN_GENERAL:
					EncounterMask |= (1 << DATA_FROSTSWORN_GENERAL);
					if (data == DONE)
					{
						if (Creature* c = instance->GetCreature(NPC_LichKingGUID))
							c->SetVisible(true);
						if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
							c->SetVisible(true);
					}
					break;
				case ACTION_SPIRITUAL_REFLECTIONS_COPY:
					{
						uint8 i=0;
						Map::PlayerList const& pl = instance->GetPlayers();
						for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
							if (Player* p = itr->GetSource())
								if (p->IsAlive() && !p->IsGameMaster())
									if (Creature* c = instance->GetCreature(NPC_SpiritualReflectionGUID[i++]))
									{
										if (!c->IsAlive())
											c->Respawn();
										c->SetDisableGravity(true);
										c->SetCanFly(true);
										c->SetVisible(true);

										Item* i;
										i = p->GetWeaponForAttack(BASE_ATTACK);
										c->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, i ? i->GetEntry() : 0);
										i = p->GetWeaponForAttack(OFF_ATTACK);
										c->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, i ? i->GetEntry() : 0);
										i = p->GetWeaponForAttack(RANGED_ATTACK);
										c->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, i ? i->GetEntry() : 0);
										p->CastSpell(c, SPELL_HOR_CLONE, true);
										p->CastSpell(c, SPELL_HOR_CLONE_NAME, true);
									}
					}
					break;
				case ACTION_SPIRITUAL_REFLECTIONS_ACTIVATE:
					if (Creature* fg = instance->GetCreature(NPC_FrostswornGeneralGUID))
						for (uint8 i=0; i<5; ++i)
							if (Creature* c = instance->GetCreature(NPC_SpiritualReflectionGUID[i]))
								if (c->IsVisible())
								{
									c->SetInCombatWithZone();
									c->SetDisableGravity(false);
									c->SetCanFly(false);
									c->GetMotionMaster()->MoveJump(fg->GetPositionX(), fg->GetPositionY(), fg->GetPositionZ(), 20.0f, 10.0f);
								}
					break;
				case ACTION_SPIRITUAL_REFLECTIONS_HIDE:
					for (uint8 i=0; i<5; ++i)
						if (Creature* c = instance->GetCreature(NPC_SpiritualReflectionGUID[i]))
							c->AI()->EnterEvadeMode();
					break;
				case DATA_LK_INTRO:
					EncounterMask |= (1 << DATA_LK_INTRO);
					if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
						c->AI()->DoAction(ACTION_START_INTRO);
					break;
				case ACTION_START_LK_FIGHT:
					IsDuringLKFight = true;
					DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT);
					DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT);
					break;
				case ACTION_STOP_LK_FIGHT:
					if (!IsDuringLKFight)
						break;
					instance->LoadGrid(LeaderEscapePos.GetPositionX(), LeaderEscapePos.GetPositionY());
					if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
					{
						if (!c->IsAlive())
						{
							c->Respawn();
							if (TeamIdInInstance == TEAM_ALLIANCE)
								c->UpdateEntry(NPC_JAINA_PART2);
						}
						c->DeleteThreatList();
						c->CombatStop(true);
						c->InterruptNonMeleeSpells(true);
						c->GetMotionMaster()->Clear();
						c->GetMotionMaster()->MoveIdle();
						c->UpdatePosition(LeaderEscapePos, true);
						c->StopMovingOnCurrentPos();
						c->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
						c->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
						c->SetHealth(c->GetMaxHealth()/20);
						c->AI()->Reset();
						c->setActive(false);
						c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
						c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
					}
					if (Creature* c = instance->GetCreature(NPC_LichKingGUID))
					{
						c->DeleteThreatList();
						c->CombatStop(true);
						c->InterruptNonMeleeSpells(true);
						c->GetMotionMaster()->Clear();
						c->GetMotionMaster()->MoveIdle();
						c->UpdatePosition(c->GetHomePosition(), true);
						c->StopMovingOnCurrentPos();
						c->RemoveAllAuras();
						c->AddAura(TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, c);
						c->AI()->Reset();
						c->setActive(false);
						c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
						c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
						c->SetSpeed(MOVE_RUN, c->GetCreatureTemplate()->speed_run);
					}
					IsDuringLKFight = false;
					outroTimer = 0;
					outroStep = 0;
					// no break intended
				case ACTION_DELETE_ICE_WALL:
					HandleGameObject(GO_IceWallGUID, true);
					GO_IceWallGUID = 0;
					break;
				case DATA_LICH_KING:
					if (data == DONE)
					{
						instance->LoadGrid(PathWaypoints[0].GetPositionX(), PathWaypoints[0].GetPositionY());
						EncounterMask |= (1 << DATA_LICH_KING);
						if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
							c->setActive(false);
						if (Creature* c = instance->GetCreature(NPC_LichKingGUID))
							c->setActive(false);
						IsDuringLKFight = false;
						outroStep = 1;
						outroTimer = 0;
					}
					break;
				case DATA_BATTERED_HILT:
					{
						if (EncounterMask & (1 << DATA_BATTERED_HILT))
							return;

						switch(data)
						{
							case 1: // talked to leader
								EncounterMask |= (1 << DATA_BATTERED_HILT);
								SaveToDB();
								break;
							case 2:
								if (BatteredHiltStatus)
									break;
								BatteredHiltStatus |= BHSF_STARTED;
								if (Creature* c = instance->GetCreature(NPC_AltarBunnyGUID))
									c->CastSpell(c, 70720, true);
								if (Creature* c = instance->GetCreature(NPC_UtherGUID))
									c->m_Events.AddEvent(new UtherBatteredHiltEvent(*c, 1), c->m_Events.CalculateTime(3000));
								break;
							case 3:
								if ((BatteredHiltStatus & BHSF_STARTED) == 0 || (BatteredHiltStatus & BHSF_THROWN))
									break;
								BatteredHiltStatus |= BHSF_THROWN;
								if (Creature* c = instance->GetCreature(NPC_UtherGUID))
								{
									c->AI()->Talk(SAY_BATTERED_HILT_LEAP);
									c->m_Events.AddEvent(new UtherBatteredHiltEvent(*c, 3), c->m_Events.CalculateTime(1500));
								}
								break;
							case 4:
								if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID))
								{
									c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
									c->SetSpeed(MOVE_RUN, 2.5f);
								}
								break;
							case 5:
								if (Creature* c = instance->GetCreature(NPC_UtherGUID))
									c->m_Events.AddEvent(new UtherBatteredHiltEvent(*c, 6), c->m_Events.CalculateTime(3000));
								break;
							case 6:
								if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID))
								{
									c->SetSpeed(MOVE_RUN, c->GetCreatureTemplate()->speed_run);
									c->GetMotionMaster()->MoveLand(0, c->GetPositionX(), c->GetPositionY(), 707.70f, 7.0f);
								}
								break;
							case 7:
								if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID))
								{
									c->SetReactState(REACT_AGGRESSIVE);
									c->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
									c->RemoveAurasDueToSpell(70300);
								}
								break;
							case 8:
								if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID))
									c->SetInCombatWithZone();
								break;
							case 9:
								EncounterMask |= (1 << DATA_BATTERED_HILT);
								BatteredHiltStatus |= BHSF_FINISHED;
								SaveToDB();
								break;
						}
					}
					return;
			}

			if (data == DONE)
				SaveToDB();
		}

		uint32 GetData(uint32 type) const
		{
			switch(type)
			{
				case DATA_INTRO:
				case DATA_FALRIC:
				case DATA_MARWYN:
				case DATA_FROSTSWORN_GENERAL:
				case DATA_LK_INTRO:
				case DATA_LICH_KING:
					return EncounterMask & (1 << type);
				case DATA_WAVE_NUMBER:
					return (uint32)WaveNumber;
				case DATA_BATTERED_HILT:
					return BatteredHiltStatus;
			}

			return 0;
		}

		uint64 GetData64(uint32 type) const
		{
			switch(type)
			{
				case NPC_DARK_RANGER_LORALEN:
					return NPC_GuardGUID;
				case NPC_LICH_KING_EVENT:
					return NPC_LichKingIntroGUID;
				case NPC_UTHER:
					return NPC_UtherGUID;
				case DATA_FALRIC:
					return NPC_FalricGUID;
				case DATA_MARWYN:
					return NPC_MarwynGUID;
				case NPC_LICH_KING_BOSS:
					return NPC_LichKingGUID;
				case NPC_SYLVANAS_PART2:
					return NPC_LeaderGUID;
				case NPC_ICE_WALL_TARGET:
				case NPC_ICE_WALL_TARGET+1:
				case NPC_ICE_WALL_TARGET+2:
				case NPC_ICE_WALL_TARGET+3:
					return NPC_IceWallTargetGUID[type-NPC_ICE_WALL_TARGET];
				case GO_FROSTMOURNE:
					return GO_FrostmourneGUID;
				case GO_ARTHAS_DOOR:
					return GO_ArthasDoorGUID;
				case GO_FRONT_DOOR:
					return GO_FrontDoorGUID;
			}

			return 0;
		}

		std::string GetSaveData()
		{
			OUT_SAVE_INST_DATA;

			std::ostringstream saveStream;
			saveStream << "H R " << EncounterMask;

			OUT_SAVE_INST_DATA_COMPLETE;
			return saveStream.str();
		}

		void Load(const char* in)
		{
			if (!in)
			{
				OUT_LOAD_INST_DATA_FAIL;
				return;
			}

			OUT_LOAD_INST_DATA(in);

			char dataHead1, dataHead2;
			uint32 data0;

			std::istringstream loadStream(in);
			loadStream >> dataHead1 >> dataHead2 >> data0;

			if (dataHead1 == 'H' && dataHead2 == 'R')
			{
				EncounterMask = data0;
				BatteredHiltStatus = (EncounterMask & (1 << DATA_BATTERED_HILT)) ? BHSF_FINISHED : BHSF_NONE;
			}
			else
				OUT_LOAD_INST_DATA_FAIL;

			OUT_LOAD_INST_DATA_COMPLETE;
		}

		void OnUnitDeath(Unit* unit)
		{
			if (WaveNumber && reqKillCount)
				if (unit->GetEntry() == NPC_WAVE_MERCENARY || unit->GetEntry() == NPC_WAVE_FOOTMAN || unit->GetEntry() == NPC_WAVE_RIFLEMAN || unit->GetEntry() == NPC_WAVE_PRIEST || unit->GetEntry() == NPC_WAVE_MAGE)
					if ((--reqKillCount) == 0 && WaveNumber%5 && NextWaveTimer > 5000)
						NextWaveTimer = 5000;
			
			if (unit->GetEntry() == NPC_QUEL_DELAR)
				if (Creature* c = instance->GetCreature(NPC_UtherGUID))
				{
					c->SetStandState(UNIT_STAND_STATE_STAND);
					c->SetWalk(false);
					c->GetMotionMaster()->MovePoint(0, 5313.92f, 1989.36f, 707.70f);
					c->m_Events.AddEvent(new UtherBatteredHiltEvent(*c, 9), c->m_Events.CalculateTime(7000));
				}
		}

		void RandomizeCompositionsAndShow()
		{
			uint8 r1 = urand(0,1), r2 = urand(2,3);
			for (uint8 i=0; i<5; ++i)
			{
				chosenComposition[0][i] = allowedCompositions[r1][i];
				chosenComposition[1][i] = allowedCompositions[r1 == 0 ? 1 : 0][i];
				chosenComposition[2][i] = allowedCompositions[r2][i];
				chosenComposition[3][i] = allowedCompositions[r2 == 2 ? 3 : 2][i];
			}
			bool left[4] = {true, true, true, true};
			for (uint8 k=4; k>0; --k)
			{
				uint8 r = urand(0, k-1);
				uint8 ur = 0;
				for (uint8 j=0; j<4; ++j)
					if (left[j])
					{
						if (ur == r)
						{
							left[j] = false;
							for (uint8 i=0; i<5; ++i)
								chosenComposition[8-k][i] = allowedCompositions[j+4][i];
							break;
						}
						++ur;
					}
			}

			if (bFinished5Waves)
			{
				for (; WaveNumber < 4; ++WaveNumber)
				{
					uint8 num_to_activate;
					if (WaveNumber <= 1)
						num_to_activate = 3;
					else
						num_to_activate = 4;

					for (uint8 i=0; i<num_to_activate; ++i)
					{
						uint32 entry = chosenComposition[WaveNumber][i];
						bool forward = urand(0,1) ? true : false;
						for (int8 j = (forward ? 0 : NUM_OF_TRASH-1); (forward ? j<NUM_OF_TRASH : j>=0); (forward ? ++j : --j))
							if (!TrashActive[j])
								if (Creature* c = instance->GetCreature(NPC_TrashGUID[j]))
									if (c->GetEntry() == entry)
									{
										TrashActive[j] = true;
										Unit::Kill(c, c);
										break;
									}
					}
				}
				WaveNumber = 5;
			}

			for (uint8 i=0; i<NUM_OF_TRASH; ++i)
				if (!TrashActive[i])
					if (Creature* c = instance->GetCreature(NPC_TrashGUID[i]))
					{
						c->SetVisible(true);
						c->CastSpell(c, SPELL_WELL_OF_SOULS_VISUAL, false);
					}
		}

		void AddWave1()
		{
			if (WaveNumber >= 10)
				return;

			++WaveNumber;
			if (WaveNumber >= 6)
				bFinished5Waves = true;

			DoUpdateWorldState(WORLD_STATE_HOR_COUNTER, 1);
			DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, WaveNumber);
			HandleGameObject(GO_FrontDoorGUID, false);

			// some of them could go back to spawn due to vanish, etc.
			// on activating next wave make those attack again
			for (uint8 i=0; i<NUM_OF_TRASH; ++i)
				if (TrashActive[i])
					if (Creature* c = instance->GetCreature(NPC_TrashGUID[i]))
						if (c->IsAlive() && !c->IsInCombat())
							c->AI()->DoAction(1);

			if (WaveNumber == 5 || WaveNumber == 10)
			{
				NextWaveTimer = 0;
				if (WaveNumber == 5)
				{
					if (Creature* falric = instance->GetCreature(NPC_FalricGUID))
					{
						if (falric->IsAlive())
							falric->AI()->DoAction(1);
						else
							NextWaveTimer = 1;
					}
				}
				else
				{
					if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID))
						if (marwyn->IsAlive()) // should always be true, but just in case
							marwyn->AI()->DoAction(1);
				}
			}
			else
			{
				NextWaveTimer = 65000;

				uint8 num_to_activate = 5;
				if (WaveNumber <= 2)
					num_to_activate = 3;
				else if (WaveNumber <= 4)
					num_to_activate = 4;

				reqKillCount += num_to_activate;

				for (uint8 i=0; i<num_to_activate; ++i)
				{
					uint32 entry = chosenComposition[WaveNumber-(WaveNumber > 5 ? 2 : 1)][i];
					bool forward = urand(0,1) ? true : false;
					for (int8 j = (forward ? 0 : NUM_OF_TRASH-1); (forward ? j<NUM_OF_TRASH : j>=0); (forward ? ++j : --j))
						if (!TrashActive[j])
							if (Creature* c = instance->GetCreature(NPC_TrashGUID[j]))
								if (c->GetEntry() == entry)
								{
									TrashActive[j] = true;
									c->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE);
									c->AI()->DoAction(1);
									break;
								}
				}
			}
		}

		void DoWipe1()
		{
			if (!WaveNumber)
				return;

			DoUpdateWorldState(WORLD_STATE_HOR_COUNTER, 0);
			DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, 0);
			HandleGameObject(GO_FrontDoorGUID, true);

			TrashCounter = NUM_OF_TRASH;
			WaveNumber = 0;
			NextWaveTimer = 0;
			memset(&chosenComposition, 0, sizeof(chosenComposition));

			for (uint8 i=0; i<NUM_OF_TRASH; ++i)
				if (TrashActive[i])
					if (Creature* c = instance->GetCreature(NPC_TrashGUID[i]))
					{
						c->DeleteThreatList();
						c->CombatStop(true);
						c->InterruptNonMeleeSpells(true);
						c->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE);
						c->Respawn(true);
						c->UpdatePosition(c->GetHomePosition(), true);
						c->StopMovingOnCurrentPos();
					}
			memset(&TrashActive, 0, sizeof(TrashActive));

			if (Creature* falric = instance->GetCreature(NPC_FalricGUID))
				falric->AI()->EnterEvadeMode();
			if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID))
				marwyn->AI()->EnterEvadeMode();

			ResumeFirstEventTimer = 5000;
			ResumeFirstEventStep = 2;
			reqKillCount = 0;
		}

		void Update(uint32 diff)
		{
			if (!instance->HavePlayers())
				return;

			if (CheckPlayersTimer <= diff)
			{
				CheckPlayersTimer = 5000;
				if ((EncounterMask & (1 << DATA_INTRO)) && !(EncounterMask & (1 << DATA_MARWYN))) // first event
				{
					Map::PlayerList const& pl = instance->GetPlayers();
					if (WaveNumber || NextWaveTimer)
					{
						bool allDead = true;
						bool outOfRange = false;
						for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
							if (Player* p = itr->GetSource())
							{
								if (p->IsGameMaster())
									continue;
								if (p->IsAlive())
									allDead = false;
								if (p->GetExactDist2d(&CenterPos) > MAX_DIST_FROM_CENTER_IN_COMBAT)
								{
									outOfRange = true;
									break;
								}
							}
						if (allDead || outOfRange)
							DoWipe1();
					}
					else if (!ResumeFirstEventTimer)
					{
						bool allInRangeAndAlive = (instance->GetPlayersCountExceptGMs() > 0 ? true : false);
						for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
							if (Player* p = itr->GetSource())
								if (!p->IsGameMaster() && (p->GetExactDist2d(&CenterPos) > MAX_DIST_FROM_CENTER_TO_START || !p->IsAlive()))
								{
									allInRangeAndAlive = false;
									break;
								}
						if (allInRangeAndAlive)
						{
							ResumeFirstEventTimer = 1;
							ResumeFirstEventStep = 0;
						}
					}
				}
			}
			else
				CheckPlayersTimer -= diff;

			if (NextWaveTimer)
			{
				if (NextWaveTimer <= diff)
				{
					NextWaveTimer = 0;
					AddWave1();
				}
				else
					NextWaveTimer -= diff;
			}

			if (ResumeFirstEventTimer)
			{
				if (ResumeFirstEventTimer <= diff)
				{
					switch (ResumeFirstEventStep)
					{
						case 0:
							if (Creature* pFalric = instance->GetCreature(NPC_FalricGUID))
							{
								pFalric->UpdatePosition(5274.9f, 2039.2f, 709.319f, 5.4619f, true);
								pFalric->StopMovingOnCurrentPos();
								pFalric->SetVisible(true);
								if (pFalric->IsAlive())
								{
									pFalric->GetMotionMaster()->MovePoint(0, FalricMovePos);
									if (Aura* a = pFalric->AddAura(SPELL_SHADOWMOURNE_VISUAL, pFalric))
										a->SetDuration(8000);
								}
							}
							if (Creature* pMarwyn = instance->GetCreature(NPC_MarwynGUID))
							{
								pMarwyn->UpdatePosition(5343.77f, 1973.86f, 709.319f, 2.35173f, true);
								pMarwyn->StopMovingOnCurrentPos();
								pMarwyn->SetVisible(true);
								if (pMarwyn->IsAlive())
								{
									pMarwyn->GetMotionMaster()->MovePoint(0, MarwynMovePos);
									if (Aura* a = pMarwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, pMarwyn))
										a->SetDuration(8000);
								}

								pMarwyn->MonsterTextEmote("Spirits appear and surround the altar!", 0, true);
							}
							++ResumeFirstEventStep;
							ResumeFirstEventTimer = 7500;
							break;
						case 1:
							if (Creature* pFalric = instance->GetCreature(NPC_FalricGUID))
								pFalric->AI()->Talk(SAY_FALRIC_INTRO_2);
							SetData(ACTION_SHOW_TRASH, 1);
							ResumeFirstEventStep = 0;
							ResumeFirstEventTimer = 0;
							NextWaveTimer = 7000;
							break;
						default:
							for (uint8 i=0; i<NUM_OF_TRASH; ++i)
								if (Creature* c = instance->GetCreature(NPC_TrashGUID[i]))
									c->SetVisible(false);
							if (Creature* falric = instance->GetCreature(NPC_FalricGUID))
								falric->SetVisible(false);
							if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID))
								marwyn->SetVisible(false);
							ResumeFirstEventStep = 0;
							ResumeFirstEventTimer = 0;
							break;
					}
				}
				else
					ResumeFirstEventTimer -= diff;
			}

			if (outroStep)
			{
				if (outroTimer <= diff)
				{
					switch (outroStep)
					{
						case 1:
							if (Creature* lk = instance->GetCreature(NPC_LichKingGUID))
							{
								lk->UpdatePosition(PathWaypoints[PATH_WP_COUNT-2], true);
								lk->StopMovingOnCurrentPos();
								lk->RemoveAllAuras();
								lk->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02);
								if (!lk->IsVisible())
									lk->SetVisible(true);
								if (Creature* leader = instance->GetCreature(NPC_LeaderGUID))
								{
									leader->UpdatePosition(PathWaypoints[PATH_WP_COUNT-1], true);
									leader->StopMovingOnCurrentPos();
									leader->RemoveAllAuras();
									leader->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_READY1H);
									if (!leader->IsVisible())
										leader->SetVisible(true);
									lk->CastSpell(leader, SPELL_HARVEST_SOUL, false);
								}
							}
							++outroStep;
							outroTimer = 500;
							break;
						case 2:
							{
								uint32 entry = TeamIdInInstance == TEAM_ALLIANCE ? GO_THE_SKYBREAKER : GO_ORGRIMS_HAMMER;
								T1 = sTransportMgr->CreateTransport(entry, 0, instance);

								++outroStep;
								outroTimer = TeamIdInInstance == TEAM_ALLIANCE ? 10000 : 10500;
							}
							break;
						case 3:
							if (T1)
								T1->EnableMovement(false);
							if (Creature* c = instance->GetCreature(NPC_ShipCaptainGUID))
								c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_FIRE_ALLY : SAY_FIRE_HORDE);
							if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
							{
								c->RemoveAllAuras();
								c->CastSpell(c, SPELL_GUNSHIP_CANNON_FIRE_PERIODIC, true);
							}
							if (Creature* c = instance->GetCreature(NPC_LichKingGUID))
							{
								c->InterruptNonMeleeSpells(true);
								c->RemoveAllAuras();
							}
							++outroStep;
							outroTimer = 5000;
							break;
						case 4:
							HandleGameObject(GO_CaveInGUID, false);
							++outroStep;
							outroTimer = 3000;
							break;
						case 5:
							if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
								c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
							if (Creature* c = instance->GetCreature(NPC_LichKingGUID))
							{
								c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
								c->DeleteThreatList();
								c->CombatStop(true);
								c->InterruptNonMeleeSpells(true);
								c->SetVisible(false);
							}
							if (instance->IsHeroic())
								instance->ToInstanceMap()->PermBindAllPlayers();
							if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
								c->CastSpell(c, SPELL_ACHIEVEMENT_CHECK, true);
							++outroStep;
							outroTimer = 1000;
							break;
						case 6:
							if (T1)
								T1->EnableMovement(true);
							++outroStep;
							outroTimer = 3500;
							break;
						case 7:
							if (T1)
								T1->EnableMovement(false);
							if (Creature* leader = instance->GetCreature(NPC_LeaderGUID))
							{
								uint8 index = TeamIdInInstance == TEAM_ALLIANCE ? 0 : 1;
								for (uint8 i=0; i<3; ++i)
									if (StairsPos[index][i].GetPositionX())
										if (GameObject* go = leader->SummonGameObject(TeamIdInInstance == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false))
											go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);

								//Position pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyPortalPos : HordePortalPos;
								//leader->SummonGameObject(GO_PORTAL_TO_DALARAN, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400);
								//pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyChestPos : HordeChestPos;
								//leader->SummonGameObject(instance->GetSpawnMode() ? GO_CHEST_HEROIC : GO_CHEST_NORMAL, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400);
							}
							++outroStep;
							outroTimer = 1000;
							break;
						case 8:
							if (Creature* c = instance->GetCreature(NPC_ShipCaptainGUID))
								c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_ONBOARD_ALLY : SAY_ONBOARD_HORDE);
							if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
							{
								c->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
								c->GetMotionMaster()->MovePoint(0, WalkCaveInPos);
							}
							++outroStep;
							outroTimer = 6000;
							break;
						case 9:
							if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
								c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_FINAL_ALLY : SAY_FINAL_HORDE);
							HandleGameObject(GO_CaveInGUID, true);
							++outroStep;
							outroTimer = 11000;
							break;
						case 10:
							++outroStep;
							outroTimer = 0;
							for (Map::PlayerList::const_iterator itr = instance->GetPlayers().begin(); itr != instance->GetPlayers().end(); ++itr)
								if (Player* p = itr->GetSource())
									p->KilledMonsterCredit(NPC_WRATH_OF_THE_LICH_KING_CREDIT, 0);
							if (TeamIdInInstance == TEAM_ALLIANCE)
								if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
								{
									c->AI()->Talk(SAY_FINAL_ALLY_SECOND);
									outroTimer = 10000;
								}
							break;
						case 11:
							if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
								c->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
							++outroStep;
							outroTimer = 300*1000;
							break;
						case 12:
							outroStep = 0;
							outroTimer = 0;
							if (T1)
								T1->setActive(false);
							break;
					}
				}
				else
					outroTimer -= diff;
			}
		}
	};
};

void AddSC_instance_halls_of_reflection()
{
	new instance_halls_of_reflection();
}
